#include "park_point.h"

namespace application {
namespace park {

ParkPoint::ParkPoint(const QString& pointId, int floor, const kernel::Position& position,
                     std::shared_ptr<kernel::ILogger> logger, QObject* parent)
    : QObject(parent)
    , m_pointId(pointId)
    , m_floor(floor)
    , m_position(position)
    , m_logger(logger)
{
}

bool ParkPoint::occupy(int agvId) {
    if (m_isOccupied) {
        if (m_logger) {
            m_logger->warning(QString("停车点 %1 已被占用 (AGV: %2)")
                .arg(m_pointId).arg(m_currentOccupyingAgvId));
        }
        return false;
    }

    m_isOccupied = true;
    m_currentOccupyingAgvId = agvId;

    if (m_logger) {
        m_logger->info(QString("停车点 %1 被 AGV %2 占用").arg(m_pointId).arg(agvId));
    }

    emit occupationChanged(true, agvId);
    return true;
}

bool ParkPoint::releaseOccupation() {
    if (!m_isOccupied) {
        return false;
    }

    int previousAgvId = m_currentOccupyingAgvId;
    m_isOccupied = false;
    m_currentOccupyingAgvId = -1;

    if (m_logger) {
        m_logger->info(QString("停车点 %1 释放占用 (之前 AGV: %2)").arg(m_pointId).arg(previousAgvId));
    }

    emit occupationChanged(false, previousAgvId);
    return true;
}

bool ParkPoint::preOccupy(int agvId) {
    if (m_preOccupyingAgvId != -1 && m_preOccupyingAgvId != agvId) {
        if (m_logger) {
            m_logger->warning(QString("停车点 %1 已被预占用 (AGV: %2)")
                .arg(m_pointId).arg(m_preOccupyingAgvId));
        }
        return false;
    }

    m_preOccupyingAgvId = agvId;

    if (m_logger) {
        m_logger->debug(QString("停车点 %1 被 AGV %2 预占用").arg(m_pointId).arg(agvId));
    }

    emit preOccupationChanged(true, agvId);
    return true;
}

bool ParkPoint::releasePreOccupation(int agvId) {
    if (m_preOccupyingAgvId != agvId) {
        return false;
    }

    m_preOccupyingAgvId = -1;

    if (m_logger) {
        m_logger->debug(QString("停车点 %1 释放预占用 (AGV: %2)").arg(m_pointId).arg(agvId));
    }

    emit preOccupationChanged(false, agvId);
    return true;
}

void ParkPoint::setArea(std::shared_ptr<area::Area> area) {
    if (m_area) {
        disconnect(m_area.get(), nullptr, this, nullptr);
    }

    m_area = area;

    if (m_area) {
        connect(m_area.get(), &area::Area::areaEntered, this, &ParkPoint::onAreaEntered);
        connect(m_area.get(), &area::Area::areaExited, this, &ParkPoint::onAreaExited);
    }
}

void ParkPoint::onAreaEntered(int agvId, const QString& areaId) {
    Q_UNUSED(areaId);
    occupy(agvId);
}

void ParkPoint::onAreaExited(int agvId, const QString& areaId) {
    Q_UNUSED(areaId);
    if (m_currentOccupyingAgvId == agvId) {
        releaseOccupation();
    }
}

} // namespace park
} // namespace application
